/**
 * FindConnectedRegion.cpp 
 * C++ source of the bing feature function
 * @author xyyuan
 * @date Mar, 4, 2014
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <string>

#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

using namespace std;
using namespace cv;

#include "Global.h"
#include "BingFeature.h"

BingFeature::BingFeature()
{
}

BingFeature::~BingFeature()
{
}

/**
 * Set the original image 
 *
 * @param string filename
 *					the file name of the original image
 * @return bool
 */
bool BingFeature::setOrigImage(string filename) {
	// Read the image
	origImage = imread(filename);
	calNGImage();
	return true;
}

/**
 * Set the original image 
 * @param Mat image
 *					the Matrix of the original image
 * @return bool
 */
bool BingFeature::setOrigImage(Mat image) {
	// Set the original image
	origImage = image;
	calNGImage();
	return true;
}

/**
 * Calculate to  get the Normed Gradient image
 * @return bool
 */
bool BingFeature::calNGImage() {
	// Get the width and height
	Mat blackImage;
	cvtColor(origImage, blackImage, CV_BGR2GRAY);
	int _row = blackImage.rows;
	int _col = blackImage.cols;
	// Initiate the NG matrix
	NGImage = Mat::zeros(_row, _col, CV_8UC1);	
	// Calculate the gradient
	for (int i = 0; i < _row; i++) {
		for (int j = 0; j < _col; j++) {
			int _drow;
			int _dcol;
			// Calculate gradient in row direction
			if (i == 0)
				_drow = abs((int)blackImage.at<uchar>(i+1, j) - (int)blackImage.at<uchar>(i, j)) * 2;
			else if (i == _row - 1)
				_drow = abs((int)blackImage.at<uchar>(i, j) - (int)blackImage.at<uchar>(i-1, j)) * 2;
			else _drow = abs((int)blackImage.at<uchar>(i+1, j) - (int)blackImage.at<uchar>(i-1, j));
			// Calculate gradient in col direction
			if (j == 0)
				_dcol = abs((int)blackImage.at<uchar>(i, j+1) - (int)blackImage.at<uchar>(i, j)) * 2;
			else if (j == _col - 1)
				_dcol = abs((int)blackImage.at<uchar>(i, j) - (int)blackImage.at<uchar>(i, j-1)) * 2;
			else _dcol = abs((int)blackImage.at<uchar>(i, j+1) - (int)blackImage.at<uchar>(i, j-1));
			// Compare
			int _total = _drow + _dcol < 255 ? _drow + _dcol : 255;
			NGImage.at<uchar>(i, j) = _total;
		}
	}
// 	imshow("1",NGImage);
// 	waitKey(0);
	return true;
}

/**
 * Calculate to  get the Normed Gradient image
 * @return bool
 */
Mat BingFeature::calNGImage(Mat input) {
	// Get the width and height
	Mat blackImage;
	Mat outImage;
	cvtColor(input, blackImage, CV_BGR2GRAY);
	int _row = blackImage.rows;
	int _col = blackImage.cols;
	// Initiate the NG matrix
	outImage = Mat::zeros(_row, _col, CV_8UC1);	
	// Calculate the gradient
	for (int i = 0; i < _row; i++) {
		for (int j = 0; j < _col; j++) {
			int _drow;
			int _dcol;
			// Calculate gradient in row direction
			if (i == 0)
				_drow = abs((int)blackImage.at<uchar>(i+1, j) - (int)blackImage.at<uchar>(i, j)) * 2;
			else if (i == _row - 1)
				_drow = abs((int)blackImage.at<uchar>(i, j) - (int)blackImage.at<uchar>(i-1, j)) * 2;
			else _drow = abs((int)blackImage.at<uchar>(i+1, j) - (int)blackImage.at<uchar>(i-1, j));
			// Calculate gradient in col direction
			if (j == 0)
				_dcol = abs((int)blackImage.at<uchar>(i, j+1) - (int)blackImage.at<uchar>(i, j)) * 2;
			else if (j == _col - 1)
				_dcol = abs((int)blackImage.at<uchar>(i, j) - (int)blackImage.at<uchar>(i, j-1)) * 2;
			else _dcol = abs((int)blackImage.at<uchar>(i, j+1) - (int)blackImage.at<uchar>(i, j-1));
			// Compare
			int _total = _drow + _dcol < 255 ? _drow + _dcol : 255;
			outImage.at<uchar>(i, j) = _total;
		}
	}
// 	imshow("1",outImage);
// 	waitKey(0);
	return outImage;
}

/**
 * Show resized 8*8 NG feature
 *
 * @param Rect rect
 *					the rect of the detection area
 * @param strign windowname
 *					the name of the show window
 * @return
 */
bool BingFeature::showNGFeature(Rect rect, string windowname) {
	// Get the mat
	Mat area = origImage(rect);
	imshow(windowname+windowname, area);
	resize(area, area, Size(8, 8));
	Mat showMat;
	showMat = calNGImage(area);
	// Resize	
	resize(showMat, showMat, Size(400, 400), 0, 0, CV_INTER_NN);
	imshow(windowname, showMat);
	return true;
}

/**
 * Show resized 8*8 NG feature
 *
 * @param Rect rect
 *					the rect of the detection area
 * @return
 */
bool BingFeature::showNGFeature(Rect rect) {
	return showNGFeature(rect, string("NGFeature"));
}